home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume15 / modem-ctl < prev    next >
Encoding:
Internet Message Format  |  1988-05-24  |  35.1 KB

  1. Subject:  v15i010:  UUCP/CU access on one modem
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: Dave Settle <No net address>
  6. Posting-number: Volume 15, Issue 10
  7. Archive-name: ultrix-modem
  8.  
  9. [  Seems oriented toward System V-oid machines...  --r$  ]
  10.  
  11.     I'm submitting the new version of 'modem', a program
  12. to allow a line connected to a modem to be used for bi-directional
  13. uucp/cu accesses.
  14.  
  15.     It functionally replaces 'uugetty', but provides a more sophisticated
  16. method of talking to intelligent modems, which can screw up uugetty by
  17. talking too much.
  18.  
  19.     The new version now has support for hardware DCD detection, which
  20. allows the shell to be hungup when the line is dropped.
  21.  
  22. Cheers,
  23.     Dave.
  24.  
  25. #! /bin/sh
  26. # This is a shell archive, meaning:
  27. # 1. Remove everything above the #! /bin/sh line.
  28. # 2. Save the resulting text in a file.
  29. # 3. Execute the file with /bin/sh (not csh) to create:
  30. #    README
  31. #    modem.1
  32. #    Makefile
  33. #    modem.h
  34. #    modem.c
  35. #    uchange.c
  36. #    sendex.c
  37. #    io.c
  38. #    line.c
  39. #    statelook.c
  40. export PATH; PATH=/bin:/usr/bin:$PATH
  41. echo shar: "extracting 'README'" '(2276 characters)'
  42. if test -f 'README'
  43. then
  44.     echo shar: "will not over-write existing file 'README'"
  45. else
  46. cat << \SHAR_EOF > 'README'
  47. Modem: A bi-directional uugetty replacement.
  48.  
  49. "Modem" works just like "uugetty", and allows incoming and outgoing calls 
  50. through the same port.
  51.  
  52. In addition, it allows provides additional facilities:
  53.  
  54. 1/.    Option to insert a uucp-style send-expect conversation to
  55. initialise the modem.
  56.  
  57. 2/.    Code to spawn getty at the correct speed, if you have a modem that
  58. can sense the speed of incoming calls.
  59.  
  60. 3/.    Autologout facility, if there is no activity on the modem for
  61. a specified period of time.
  62.  
  63. 4/.    Log of all connected calls.
  64.  
  65. 5/.    Option to run "who" and "ps" on the port, when connected,
  66. if you're really security-concious.
  67.  
  68. 6/.    Correct handling of DCD (carrier detect) signals from the modem.
  69.  
  70. 7/.    Works happily with "uucp", "cu", and "kermit", which are not aware
  71. that "modem" is running. [NB Slight change necessary to uucp dialer script
  72. required]
  73.  
  74. 8/.    State-changing code, which allows you to set the modem in a state
  75. related to the time of day. Useful if you want it only to auto-answer
  76. when you're not there, and want to use it as a telephone otherwise.
  77. [Thanks to jack@swlabs.uucp for this code.]
  78.  
  79.  
  80. It works fine on my modem, which talks too much for uugetty to be able to
  81. handle it!
  82.  
  83.  
  84. For your local site, you have to do the following:
  85.  
  86. Put this line in /etc/inittab
  87. XX:2:respawn:/usr/lib/modem ttyXX        where ttyXX is your modem line
  88.  
  89. Make sure that your dialer script is prepared to:
  90.  
  91.     a) sleep for > 1 sec BEFORE reading the first reply from the modem
  92.     b) accept that the first character sent by the modem will NOT get there
  93.  
  94. e.g. My Hayes dialer script is NORMALLY
  95.  
  96.     ... AT OK ATDP\T CONNECT
  97.  
  98. but MUST be modified to
  99.  
  100.     ... AT\r\D OK ATDP\T CONNECT          #( \D is a 2-sec pause )
  101.  
  102.  
  103. Modify the included dialer script to talk to YOUR modem, if you have a non-
  104. supported modem type. Please let me have your scripts, so that I can include
  105. them in future releases.
  106.  
  107. Modify the speed-detection routine, if your modem is not a hayes-compatible
  108.  
  109. Modify "locked()" to read YOUR lock directory - but see the makefile options
  110. for various lockfile protocols.
  111.  
  112. If necessary, modify the wiring to the modem so that DCD is asserted
  113. when the modem is online, but not asserted at other times.  This is
  114. necessary for the modem to generate a hangup signal when a remote site
  115. disconnects. 
  116.  
  117. SHAR_EOF
  118. if test 2276 -ne "`wc -c < 'README'`"
  119. then
  120.     echo shar: "error transmitting 'README'" '(should have been 2276 characters)'
  121. fi
  122. fi
  123. echo shar: "extracting 'modem.1'" '(2065 characters)'
  124. if test -f 'modem.1'
  125. then
  126.     echo shar: "will not over-write existing file 'modem.1'"
  127. else
  128. cat << \SHAR_EOF > 'modem.1'
  129. .TH modem 1 local
  130. .SH NAME
  131. modem
  132. .SH SYNOPSIS
  133. .B "modem [speed] tty"
  134. .PP
  135. .SH DESCRIPTION
  136. .I modem
  137. is a functional replacement for \fIuugetty\fR, and allows a line connected
  138. to a modem to be used for both incoming and outgoing uucp/cu calls.
  139. .PP
  140. It has an initial conversation with the modem, so that it can be set
  141. in the correct mode, and then waits for the modem to detect an incoming
  142. call. It then spawns \fIgetty(8)\fR to login the user, after making an
  143. alteration in the file /etc/utmp, so that getty thinks it was spawned by
  144. \fIinit(8)\fR.
  145. .PP
  146. While the user remains logged on, \fImodem\rB will periodically run
  147. \fIps\fR on the line, so that it can record what the user is doing.
  148. This facility can be turned off (see WATCHIT) option, if not required.
  149. .PP
  150. If, at any point prior to the incoming call, \fImodem\fR detects an
  151. \fBoutgoing\fR call, then it exits. Just before the exit, it attempts
  152. to set the line so that it can be used by outgoing callers.
  153. .PP
  154. If \fImodem\fR detects a LOCK file when it is invoked, then it will
  155. wait until this file is removed before proceeding.
  156. .PP
  157. \fImodem\fR also enforces an idle timeout, so that it the line appears
  158. to be idle for too long, the user is logged out. This may cause problems
  159. with kermit, which doesn't update the times on the device, but uses
  160. \fI/dev/tty\fR instead.
  161. .PP
  162. The optional \fBspeed\fR argument can be used to force \fImodem\fR to talk
  163. to the modem at the specified speed, otherwise it will talk at 1200 baud.
  164. .PP
  165. The tty name should be of the form \fBtty44\fR.
  166. .SH EXAMPLES
  167. .PP
  168. 44:2:respawn:/usr/lib/modem tty44
  169. .PP
  170. 1a:234:respawn:/usr/lib/modem 2400 tty1a
  171. .PP
  172. .SH FILES
  173. /dev/\fI<tty>\fB
  174. .PP
  175. /usr/spool/uucp/modem.log
  176. .SH SEE ALSO
  177. getty(8), uugetty(8), sh(1), ps(1), who(1), utmp(4)
  178. .SH BUGS
  179. The code for hardware DCD detection support is new.
  180. .PP
  181. There are still some unexplained diagnostics in my log file, mainly about
  182. write(1) calls failing to write characters.
  183. .PP
  184. You will have to modify some source code if your modem and/or system is
  185. different from mine (speed configuration and lock files).
  186. SHAR_EOF
  187. if test 2065 -ne "`wc -c < 'modem.1'`"
  188. then
  189.     echo shar: "error transmitting 'modem.1'" '(should have been 2065 characters)'
  190. fi
  191. fi
  192. echo shar: "extracting 'Makefile'" '(1328 characters)'
  193. if test -f 'Makefile'
  194. then
  195.     echo shar: "will not over-write existing file 'Makefile'"
  196. else
  197. cat << \SHAR_EOF > 'Makefile'
  198. #
  199. # new makefile for modem.
  200. #
  201. # if your lockfile is:
  202. # /usr/spool/uucp/LCK..<system>        No defines needed.
  203. # /usr/spool/locks/LCK..<system>    -DOL3B2
  204. # /usr/spool/locks/LCK.L.<system>    -DHDB
  205. #
  206. # New definitions:
  207. #    HDB:        If you have Honey-Danber UUCP (Thanks Rick)
  208. #    OL3B2:        If you have an Olivetti 3B2
  209. #    SPEEDCONFIG:    If you have a modem that tells you the speed of incoming
  210. #            calls (In ASCII - 300(or \r), 1200, 2400, 1275, 7512)
  211. #            If your modem says different things, hack the code
  212. #    WATCHIT:    If you want "who" and "ps" run periodically to check
  213. #            what's going on.
  214. #    HAYES        If you have a Hayes-type modem.
  215. #    JSET:        If you have an AT&T Aztec modem (Thanks Rick).
  216. #    DEBUG:        See what's going on.
  217. #    SLOW:        Wait 1 sec between each character written to the modem. 
  218. #    STATES        If you want to use Jack's state-changing stuff.
  219. #
  220. # check "modem.h" for additional options on default modem speed and timezone.
  221. #
  222. CFLAGS = -DOL3B2 -DSPEEDCONFIG -DWATCHIT -DHAYES 
  223. PARTS = modem.o uchange.o sendex.o io.o line.o statelook.o
  224. # LIBS = -lg
  225.  
  226. modem: ${PARTS}
  227.     rm -f modem
  228.     cc ${PARTS} -o modem ${LIBS}
  229.  
  230. install: modem
  231.     mv /etc/modem /etc/modem.old
  232.     cp modem /etc
  233.     
  234. lint:
  235.     lint ${CFLAGS} ${PARTS:.o=.c}
  236.     
  237. ${PARTS}: modem.h Makefile
  238.  
  239. shar:
  240.     shar -cv README modem.1 Makefile modem.h ${PARTS:.o=.c} > modem.shar
  241.  
  242.  
  243. man:
  244.     nroff -man modem.1 > modem.man
  245. SHAR_EOF
  246. if test 1328 -ne "`wc -c < 'Makefile'`"
  247. then
  248.     echo shar: "error transmitting 'Makefile'" '(should have been 1328 characters)'
  249. fi
  250. fi
  251. echo shar: "extracting 'modem.h'" '(2898 characters)'
  252. if test -f 'modem.h'
  253. then
  254.     echo shar: "will not over-write existing file 'modem.h'"
  255. else
  256. cat << \SHAR_EOF > 'modem.h'
  257. /*
  258.  * some constants for your modem
  259.  */
  260.  
  261. #define TIMEZONE "TZ=GMT0BST"        /* time zone you operate in    */
  262. #define DEFSPEED "1200"            /* speed your modem likes most    */
  263.  
  264. #define WTIME 5                /* default wait time         */
  265.  
  266. #define LOGFILE "/usr/spool/uucp/modem.log"        /* log file */
  267.  
  268. #define max(a,b) ((a) > (b) ? (a) : (b))
  269. #define min(a,b) ((a) < (b) ? (a) : (b))
  270.  
  271. #define MINUTES    60
  272. #define IDLETIME 5*MINUTES                /* autologout time */
  273. #ifdef WATCHIT
  274. #define SPYTIME 1*MINUTES
  275. #else
  276. #define SPYTIME IDLETIME
  277. #endif
  278.  
  279. #define GRACETIME    5    /* time to wait for signal to take effect */
  280.  
  281. extern int errno;
  282.  
  283. #ifdef MAINDEF
  284. #define EXTERN
  285. #else
  286. #define EXTERN extern
  287. #endif
  288.  
  289. long time();
  290. int dread(), dwrite(), myread();
  291. void mywrite();
  292.  
  293. EXTERN char lockf[50];                /* argument lock file */
  294. EXTERN char dname[30];                /* device name in full - /dev/.... */
  295.  
  296. EXTERN int shell, status;            /* pid of shell, and exit status */
  297.  
  298. EXTERN int dev;                    /* device used (open fildes) */
  299. /*
  300.  * The 'reset' sequence, if the modem doesn't behave as expected.
  301.  * I still get problems with the modem not responding to 'AT'.
  302.  */
  303. #if defined(HAYES)
  304. #define RESET "\n\rAT\r\rAT\r\rAT\r\r"
  305. #else
  306. #define RESET ""
  307. #endif
  308. /*
  309.  * The 'conversation' necessary to get your modem into a 'listening' state.
  310.  * The converasation should complete iff an incoming call is connected.
  311.  * If using Jack's states, set up your states below. Each modem line
  312.  * must have flags set to indicate in which state(s) it can be executed.
  313.  * If you're not using the STATES stuff, leave them at zero.
  314.  */
  315. #define SPK            0x0001    /* Speaker control */
  316. #define    AA            0x0002    /* Auto Answer Control */
  317.  
  318. struct conv {
  319.     char *c_send;
  320.     char *c_expect;
  321.     int c_wait;        /* time to wait for c_expect */
  322.     int c_flags;        /* flags for matching with the state. */
  323. };
  324.  
  325. #ifdef MAINDEF
  326.  
  327. struct conv ring[] = {
  328.  
  329. #if defined(HAYES)
  330.     {"AT\r", "OK", WTIME, AA | SPK },    /* anyone there? */
  331.     {"ATM0\r", "OK", WTIME, AA | SPK },    /* turn OFF speaker */
  332.     {"ATS0=0\r", "OK", WTIME, AA | SPK},    /* DISABLE auto-answer */
  333.     {"ATS0=1\r", "OK", WTIME, AA},        /* maybe enable auto answer */
  334.     {"ATM1\r", "OK", WTIME, SPK},        /* maybe turn speaker on */
  335.     {"ATX1V1\r", "OK", WTIME, AA | SPK },    /* turn on responses */ 
  336.     {"ATS24=3\r", "OK", WTIME, AA | SPK},    /* enable speed-seeking */
  337.     {"", "RING", 0, AA | SPK},        /* wait (indefinately) for RING in */
  338.     {"", "CONNECT", 20, AA | SPK},        /* wait for call to be connected */
  339.     {NULL, NULL, 0, 0}            /* finished */
  340.  
  341. #else /* defined (HAYES) */
  342. #if defined(JSET)    /* AT&T Aztec Protocol */
  343.     {"\\d\r\\d", "MODEM: ", WTIME, 0 },    /* anyone there? */
  344.     {"", "DATA", 3600, 0},        /* wait (1 hour) for RING in */
  345.     {NULL, NULL, 0, 0}            /* Should be indefinite, but prevent
  346.                        problems if modem gets wedged */
  347.  
  348. #else /* defined (JSET) */
  349.     {NULL, NULL, 0, 0}            /* no init conversation */
  350.  
  351. #endif /* defined (JSET) */
  352. #endif /* defined (HAYES) */
  353. };
  354. #endif /* defined (MAINDEF) */
  355. SHAR_EOF
  356. if test 2898 -ne "`wc -c < 'modem.h'`"
  357. then
  358.     echo shar: "error transmitting 'modem.h'" '(should have been 2898 characters)'
  359. fi
  360. fi
  361. echo shar: "extracting 'modem.c'" '(10194 characters)'
  362. if test -f 'modem.c'
  363. then
  364.     echo shar: "will not over-write existing file 'modem.c'"
  365. else
  366. cat << \SHAR_EOF > 'modem.c'
  367. /*
  368.  * Copyright (c) Dave Settle 1987
  369.  * All rights reserved.
  370.  * Permission is granted to do anything with this program, except remove
  371.  * this copyright notice, or sell it for profit.
  372.  *
  373.  * Problems, suggestions, bug fixes etc, to:
  374.  *
  375.  * Dave Settle, SMB Business Software, Thorn EMI Datasolve
  376.  * 
  377.  * UUCP:
  378.  *     dave@smb.co.uk
  379.  *     ...!mcvax!ukc!nott-cs!smb!dave    
  380.  * 
  381.  * SMAIL:                    Voice:
  382.  *     SMB Business Software             +44 623 651651
  383.  *     High Street
  384.  *     Mansfield            Telex:
  385.  *     Nottingham NG18 1ES             37392 TECSMG
  386.  *     England    
  387.  *                     Fax:
  388.  *                          +44 623 659947
  389.  * 
  390.  * modem.c: a bi-directional "getty" to allow incoming calls AND outgoing 
  391.  * uucico's
  392.  *
  393.  * Modified by Rick Richardson for HDB uucp and AT&T Aztec protocol
  394.  *
  395.  * Modified by Jack Bonn for state logic (allows autoanswer on/off at
  396.  *                       a given time for each day of the week)
  397.  *
  398.  * Modified by Dave Settle:
  399.  *
  400.  * Code fixes:
  401.  *    hangup routine added, to make sure phone is down before script, and
  402.  *        after user disconnects.
  403.  *    Parameterised send-expect routines.
  404.  *    Minor bug fix to dread()
  405.  *    Re-enable SIGALRM in wakeup()
  406.  *    Catch all signals, to enable crashes to be detected.
  407.  *    Chmod device back to 666, so that we can use it afterwards.
  408.  *      Oct 87: fixup modem control with CLOCAL, so that remote disconnect
  409.  *        can be detected and dealt with.
  410.  *    Oct 87: fix autologout to send series of signals, not just SIGHUP
  411.  *    Oct 87: Clean up code, and distribute to other source files.
  412.  *    Nov 87: Fix lurking bug in 'expect'. Clean code for 'lint'.
  413.  *    Nov 87: Ignore SIHGUP's generated by 'hangup'.
  414.  *    Dec 87: Force getty NOT to hangup the line before login.
  415.  *    Jan 87: Open stdio file descriptors.
  416.  *
  417.  *
  418.  */
  419. #include <sys/types.h>
  420. #include <stdio.h>
  421. #include <signal.h>
  422. #include <errno.h>
  423. #include <fcntl.h>
  424. #include <termio.h>
  425. #include <sys/stat.h>
  426. #include <time.h>
  427.  
  428. #ifdef WATCHIT
  429. #include <pwd.h>
  430. struct passwd *getpwuid();
  431. #endif
  432.  
  433. #define MAINDEF
  434. #include "modem.h"        /* variable definitions */
  435. /* 
  436.  * wakeup gets called when the alarm goes off 
  437.  */
  438. wakeup(){
  439.     signal(SIGALRM, wakeup);
  440. }
  441.  
  442. fault(sig){
  443.     printf("Crashed with signal %d\n", sig);
  444.     closedown(sig);
  445. }
  446.  
  447. closedown(sig){
  448.     time_t now;
  449.     now = time((long *) 0);
  450. /*
  451.  * [Nov 87]: Since we're about to hang up the phone, 
  452.  * ignore the signal that this is going to generate.
  453.  */
  454.     signal(SIGHUP, SIG_IGN);
  455.     if(sig) printf("Caught signal %d\n", sig);
  456.     printf("Closedown at %s", asctime(localtime(&now)));
  457. /*
  458.  * Oct 87: new addition for SIGHUP. We receive this signal when    the line
  459.  * is disconnected by a remote caller. Since the line is dead, so should
  460.  * the shell be (it got SIGHUP same as us); log it out anyway, even if it's
  461.  * trying to ignore it.
  462.  */
  463.     if((sig == SIGHUP) && shell) autologout(shell);
  464. /*
  465.  * change the value in utmp back to our pid.
  466.  */        
  467.     if(shell) uchange(shell, getpid());    /* back to normal */
  468. /*
  469.  * clear modem line, which should also hangup the phone (if it wasn't already).
  470.  */    
  471.     hangup(dev);
  472.     close(dev);
  473. /*
  474.  * chmod the device back to 666, so that uucico and cu can access it.
  475.  * NOTE: I prefer this to chown(uucp), which does not allow "cu" access.
  476.  */
  477.     chmod(dname,0666);    /* uucp access */
  478.     unlink(lockf);
  479.     if(status) printf("Logout status 0x%x\n", status);
  480.     fclose(stdout);
  481.     exit(0);
  482. }
  483.         
  484. main(argc, argv, envp)
  485. char **argv, **envp;
  486. {
  487.     long t;
  488.     char *arg[5], *speed;
  489.     int baud, i;
  490.     struct conv *p;
  491.     struct stat sbuf;
  492.     time_t now, mtime;
  493. #ifdef WATCHIT
  494.     FILE *procs;
  495.     struct passwd *pw;
  496.     char psbuff[128];
  497. #endif
  498. #ifdef SPEEDCONFIG
  499.     char c, buff[8];
  500. #endif
  501. #ifdef STATES
  502.     time_t delta, suicide;
  503.     int state;
  504. #endif
  505.     FILE *lock;
  506. /*
  507.  * catch and report all signals, but apply special treatment to legal signals
  508.  * Any program bugs get reported this way. You can get a core dump by sending
  509.  * it SIGFPE.
  510.  */
  511.      for(i=1;i<SIGUSR1;i++) signal(i, fault);
  512.      
  513.      signal(SIGHUP, SIG_IGN);
  514.      signal(SIGINT, SIG_IGN);
  515.      signal(SIGQUIT, SIG_IGN);
  516.      signal(SIGFPE, SIG_DFL);    /* you can get a core dump here */
  517.      signal(SIGALRM, wakeup);
  518.      signal(SIGTERM, closedown);
  519. /*
  520.  * Open the standard I/O file descriptors, if not already open.
  521.  * Running from init, we don't have a terminal, so output to LOGFILE.
  522.  */
  523.      if((i = open("/dev/null", 0)) == 0) {
  524.          open("/dev/null", 1);
  525.          open("/dev/null", 1);
  526.      }
  527.      else close(i);
  528.      freopen(LOGFILE, "a", stdout);
  529. #ifdef SETBUF
  530.     setbuf(stdout, NULL);            /* if setvbuf broken */
  531. #else
  532.      setvbuf(stdout, NULL, _IOLBF, 0);
  533. #endif
  534.  
  535.     if (argc < 2)
  536.     {
  537.         printf("Usage: %s <tty> [<speed>]\n", argv[0]);
  538.         sleep(5);
  539.         exit(5);
  540.     }
  541.           
  542.     sprintf(dname, "/dev/%s", argv[1]);
  543. #if defined(OL3B2)
  544.     sprintf(lockf, "/usr/spool/locks/LCK..%s", argv[1]);
  545. #else
  546. #if  defined(HDB)
  547.     sprintf(lockf, "/usr/spool/locks/LCK.L.%s", argv[1]);
  548. #else
  549.     sprintf(lockf, "/usr/spool/uucp/LCK..%s", argv[1]);
  550. #endif
  551. #endif
  552. /*
  553.  * do not start while device is locked
  554.  */
  555.      while(locked()) sleep(30);
  556.     if((dev = open(dname, O_RDWR | O_NDELAY)) == -1) {
  557.             perror(dname);
  558.             sleep(5);    /* don't go crazy with respawns */
  559.             exit(4);
  560.     }
  561.  
  562.  /*
  563.   * setup correct time zone
  564.   */
  565.     putenv(TIMEZONE);
  566.  /*
  567.   * set terminal parameters
  568.   * Additional argument (if present) can be used to force an initial speed
  569.   * (Thanks rick)
  570.   */
  571.     if(argc > 2) speed = argv[2];
  572.     else speed = DEFSPEED;
  573.     baud = findspeed(speed);
  574.     init_term(dev, baud);
  575. /*
  576.  * send-expect strings - at the end, someone has connected to the modem
  577.  */
  578. #ifdef STATES
  579. /*
  580.  * find out when the next state change is due to occur. At this point, we exit.
  581.  * The next initiation will set the modem up differently.
  582.  */
  583.     delta = duration(&state);
  584.     suicide = time((long *) 0) + delta;
  585. #endif
  586.     for(p = ring; p->c_send; p++) {
  587. #ifdef STATES
  588.         if(!applicable(p, state)) continue;
  589. #endif
  590.         send(p->c_send, mywrite);
  591. #ifdef STATES
  592.         if(expect(p->c_expect, (int)(p->c_wait ? min(p->c_wait, delta) : delta), myread)) {
  593. #else
  594.         if(expect(p->c_expect, p->c_wait, myread)) {
  595. #endif
  596.             t = time((long *) 0);
  597. #ifdef STATES
  598.             if(t >= suicide) {
  599.                 printf("Exit due to state change\n");
  600.                 exit(0);
  601.             }
  602. #endif
  603.             printf("Incoming call failed to connect on %s", asctime(localtime(&t)));
  604. /*
  605.  * we don't have to do anything special here, since no locks have been setup.
  606.  * However, since the main problems appear to be non-responding modems, send
  607.  * it some sort of 'un-wedging' sequence
  608.  */
  609.              send(RESET, mywrite);
  610.              sleep(3);
  611.             hangup(dev);
  612.             sleep(10);
  613.             ioctl(dev, TCFLSH, 2);    /* Flush both queues */
  614.             exit(3);
  615.             /*NOTREACHED*/
  616.         }
  617.     }
  618.     signal(SIGALRM, wakeup);
  619. /*
  620.  * OK - incoming call connected. Find speed (if possible), create lock file,
  621.  * then spawn getty.
  622.  * At this point, we also trap hangups, so that we can clean up after
  623.  * any incoming calls. (Hangups are now detected by the hardware).
  624.  */
  625.      signal(SIGHUP, closedown);
  626. #ifdef SPEEDCONFIG
  627.      dread(dev, &c, 1);
  628.      if(c == '\r') speed = "300";
  629.      else {
  630.          dread(dev, buff, 4);
  631.          if(!strcmp(buff, "1200")) speed = "1200";
  632.          if(!strcmp(buff, "2400")) speed = "2400";
  633.          if(!strcmp(buff, "1275")) speed = "1200";
  634.          if(!strcmp(buff, "7512")) speed = "1200";
  635.      }
  636.      baud = findspeed(speed);
  637. #endif
  638.     
  639.      t = time((long *)0);
  640.      printf("Call connected at %s on %s", speed, asctime(localtime(&t)));
  641. /*
  642.  * Someone has rung in - lock the device.
  643.  */
  644.      lock = fopen(lockf, "w");
  645.  /*
  646.   * hand over to "getty"
  647.   */
  648.      arg[0] = "getty";
  649.      arg[1] = "-h";
  650.      arg[2] = argv[1];
  651.      arg[3] = speed;
  652.     arg[4] = NULL;
  653.     
  654.     if(shell = fork()) {
  655. /*
  656.  * change the utmp pid to the "getty" process, so that it can login
  657.  */
  658.         uchange(getpid(), shell);    /* change utmp entry */
  659. #if defined(OL3B2)
  660.          fprintf(lock,"       %d\n", shell);
  661. #else
  662. #if  defined(HDB)
  663.          fprintf(lock,"%d\n", shell);
  664. #else
  665.         fwrite((char *) &shell, sizeof shell, 1, lock);
  666. #endif
  667. #endif
  668.          fclose(lock);
  669. /*
  670.  * wait for logout from shell. 
  671.  * if terminal is idle for IDLETIME, force a logout anyway
  672.  */
  673.          alarm(SPYTIME);
  674.         while((wait(&status) == -1) && (errno == EINTR)) {
  675.             if(stat(dname, &sbuf) == -1) {
  676.                 perror(dname);
  677.                 continue;
  678.             }
  679.             now = time((long *)0);
  680.             mtime = max(sbuf.st_atime, sbuf.st_mtime);
  681.  
  682.             if((now - mtime) >= IDLETIME) {
  683.                 write(dev, "autologout\r\n", 12);
  684.                 printf("Device idle - autologout at %s\n",
  685.                     asctime(localtime(&now)));
  686.                 uchange(shell, getpid());
  687.                 autologout(shell);
  688.                 break;
  689.             }
  690.  
  691. #ifdef WATCHIT
  692.             t = time((long *) 0);
  693.             pw = getpwuid((int) sbuf.st_uid);
  694.             printf("Logon user is %s on %s", pw->pw_name,
  695.                 asctime(localtime(&t)));
  696.             procs = popen("ps -ef", "r");
  697.             while(fgets(psbuff, sizeof psbuff, procs)) 
  698.                 if(partof(psbuff, argv[1]) && partof(psbuff, pw->pw_name))
  699.                     printf("%s", psbuff);
  700.             pclose(procs);
  701. #endif
  702.             alarm(SPYTIME);
  703.         }
  704.          t = time((long *) 0);
  705.         printf("Call disconnected on %s", asctime(localtime(&t)));
  706.         closedown(0);        /* remove locks etc */
  707.         /*NOTREACHED*/
  708.     }
  709.     else {
  710.         sleep(1);            /* allow changes to utmp */
  711. /*
  712.  * Re-do the termio settings, so that we can login.
  713.  * CLOCAL is removed at this point, so that a hangup will generate SIGHUP.
  714.  * Close all the files which we have open - getty expects none.
  715.  */
  716.          login_term(dev, baud);
  717.          for(i=0;i<20;i++) close(i);
  718. #ifdef    DEBUG     
  719.          printf("%d: /etc/getty %s %s\n", getpid(), arg[1], arg[2]);
  720. #endif
  721.         execve("/etc/getty", arg, envp);
  722.         printf("can't exec getty\n");
  723.         exit(1);
  724.         /* NOTREACHED */
  725.     }
  726. }
  727. /*
  728.  * check for presence of lock file
  729.  * return 1 if locked.
  730.  */
  731. locked(){
  732.     struct stat sb;
  733.     if(stat(lockf, &sb) == -1) return(0);
  734. #ifdef    DEBUG
  735.     printf("%s locked\n", lockf);
  736. #endif
  737.     return(1);
  738. }
  739. #ifdef WATCHIT
  740. /*
  741.  * partof: look for str in text. Has a bug if you look for ...xxx...
  742.  */
  743. partof(text, str)
  744. char *text, *str;
  745. {
  746.     char *needle, *p;
  747.     for(p = text, needle = str; *p ; p++) {
  748.         if(*p != *needle) needle = str;
  749.         if(*p == *needle) needle++;
  750.         if(*needle == '\0') return(1);
  751.     }
  752.     return(0);
  753. }
  754. #endif
  755. /*
  756.  * autologout: log out the child shell. Sends SIGHUP, SIGTERM, SIGKILL
  757.  * until the child exits.
  758.  */
  759. autologout(child)
  760. {
  761.     kill(child, SIGHUP);
  762.     alarm(GRACETIME);
  763.     if(wait(&status) == -1) {
  764.         kill(child, SIGTERM);
  765.         alarm(GRACETIME);
  766.         if(wait(&status) == -1) {
  767.             kill(child, SIGKILL);
  768.             alarm(GRACETIME);
  769.             if(wait(&status) == -1) {
  770.                 printf("Cannot kill child pid %d\n", child);
  771.                 status = 0;
  772.             }
  773.         }
  774.     }
  775.     alarm(0);
  776. }
  777. SHAR_EOF
  778. if test 10194 -ne "`wc -c < 'modem.c'`"
  779. then
  780.     echo shar: "error transmitting 'modem.c'" '(should have been 10194 characters)'
  781. fi
  782. fi
  783. echo shar: "extracting 'uchange.c'" '(711 characters)'
  784. if test -f 'uchange.c'
  785. then
  786.     echo shar: "will not over-write existing file 'uchange.c'"
  787. else
  788. cat << \SHAR_EOF > 'uchange.c'
  789. /*
  790.  * Copyright (c) Dave Settle, Mar 1987
  791.  * Permission is granted to do anything with this program, except remove
  792.  * this copyright notice, or sell it for profit.
  793.  *
  794.  *
  795.  * change the ut_pid value from "old" to "new".
  796.  * Attempts to do all the things that "getty" appears to do.
  797.  */
  798.  
  799. #include <sys/types.h>
  800. #include <utmp.h>
  801.  
  802. struct utmp *utmp, *getutent();
  803.  
  804. uchange(old, new)
  805. {
  806.     setutent();
  807.     while(utmp = getutent()) {
  808.         if(utmp->ut_pid == old) {
  809.             utmp->ut_pid = new;
  810.             if(strcmp(utmp->ut_user, "getty")) 
  811.                 strcpy(utmp->ut_user, "modem");
  812.             else
  813.                 strcpy(utmp->ut_user, "getty");
  814.             pututline(utmp);
  815.             endutent();
  816.             return(1);
  817.         }
  818.     }
  819.     printf("Can't find utmp entry\n");
  820.     endutent();
  821.     return(1);
  822. }
  823.  
  824. SHAR_EOF
  825. if test 711 -ne "`wc -c < 'uchange.c'`"
  826. then
  827.     echo shar: "error transmitting 'uchange.c'" '(should have been 711 characters)'
  828. fi
  829. fi
  830. echo shar: "extracting 'sendex.c'" '(1797 characters)'
  831. if test -f 'sendex.c'
  832. then
  833.     echo shar: "will not over-write existing file 'sendex.c'"
  834. else
  835. cat << \SHAR_EOF > 'sendex.c'
  836. /*
  837.  * Copyright (c) Dave Settle, Mar 1987
  838.  * Permission is granted to do anything with this program, except remove
  839.  * this copyright notice, or sell it for profit.
  840.  *
  841.  *
  842.  * sendex.c: contains the send-expect routines, beefed-up a little to
  843.  * make them more useful.
  844.  * Both "send" and "expect" now have a function, rather than
  845.  * a file descriptor. This function gets called as follows:
  846.  *
  847.  *    (int) (*rdfunc)();        [send]
  848.  *    (*wtfunc)((char *)s);        [expect]
  849.  *
  850.  */
  851.  
  852. #include <setjmp.h>
  853. #include <signal.h>
  854. #include <stdio.h>
  855. /*
  856.  * send: write the string out. Show the chars written if necessary.
  857.  */
  858. send(s, func)
  859. char *s;
  860. void (*func)();
  861. {
  862. #ifdef    DEBUG
  863.     printf("send(");
  864.     sshow(s);
  865.     printf(")\n");
  866. #endif
  867.     (*func)(s);
  868.     sleep(1);
  869. }
  870. /*
  871.  * expect: expect a string. Return 0 on success, 1 on timeout.
  872.  * chars are threaded on the needle as they match the expect string
  873.  * if one fails to match, all chars are unthreaded. 
  874.  * expect succeeds if all chars on expect string are threaded.
  875.  */
  876. jmp_buf env;
  877.  
  878. timeout(){
  879.     longjmp(env, 1);
  880. }
  881.  
  882. expect(s, t, func)
  883. char *s;
  884. int (*func)();
  885. {
  886.     char *needle = s, c;
  887.     int (*handler)();
  888.     alarm(0);
  889.     handler = signal(SIGALRM, timeout);
  890.     if(setjmp(env)) {
  891.         printf("Timeout expecting %s\n", s);
  892.         return(1);        /* fail - timeout */
  893.     }
  894.     alarm(t);                /* if zero, no timeout */
  895. #ifdef    DEBUG
  896.     printf("\nexpect(%s)\n", s);
  897. #endif
  898.     while(*needle) {
  899.         c = (*func)();
  900. #ifdef DEBUG
  901.         show(c);
  902. #endif
  903.         if(*needle != c) needle = s;
  904.         if(*needle == c) needle++;
  905.     }
  906. #ifdef    DEBUG
  907.     printf("got it\n");
  908. #endif
  909.     alarm(0);
  910.     signal(SIGALRM, handler);
  911.     return(0);
  912. }
  913. #ifdef    DEBUG
  914. /*
  915.  * sshow: show string
  916.  */
  917. sshow(s)
  918. char *s;
  919. {
  920.     while(*s) show(*s++);
  921. }
  922. show(c)
  923. char c;
  924. {
  925.     if((c < 31)) {
  926.         printf("^%c", c + '@');
  927.         if(c == '\n') putchar('\n');
  928.     }
  929.     else putchar(c);
  930.     fflush(stdout);
  931. }
  932. #endif
  933.  
  934. SHAR_EOF
  935. if test 1797 -ne "`wc -c < 'sendex.c'`"
  936. then
  937.     echo shar: "error transmitting 'sendex.c'" '(should have been 1797 characters)'
  938. fi
  939. fi
  940. echo shar: "extracting 'io.c'" '(4690 characters)'
  941. if test -f 'io.c'
  942. then
  943.     echo shar: "will not over-write existing file 'io.c'"
  944. else
  945. cat << \SHAR_EOF > 'io.c'
  946. /*
  947.  * Copyright (c) Dave Settle, March 1987
  948.  * Permission is granted to do anything with this program, except remove
  949.  * this copyright notice, or sell it for profit.
  950.  *
  951.  *
  952.  * io.c: routines to talk to the device directly.
  953.  *
  954.  * dread and dwrite act like read(2) and write(2), execpt that they always
  955.  * either succeed or exit, so the caller doesn't have to check.
  956.  *
  957.  * hangup drops the DTR line to the modem, so that it will (hopefully) hang up
  958.  * the phone line. It keeps it this way for 5 seconds.
  959.  *
  960.  * findspeed takes an ascii speed, and returns the corresponing baud rate.
  961.  *
  962.  * uuexit is a dodgy routine to make UUCP happy.
  963.  */
  964.  
  965. #include <sys/errno.h>
  966. #include <termio.h>
  967. #include <fcntl.h>
  968.  
  969. #include "modem.h"
  970.  
  971. char *sys_errlist[];        /* error list        */
  972. #define RETRY 5            /* retry failed writes    */
  973. /*
  974.  * dwrite: write some characters to the modem. 
  975.  * If your modem likes characters to be written s-l-o-w-l-y, define 'SLOW'    
  976.  */
  977. dwrite(f, s, n)
  978. int f;
  979. unsigned n;
  980. char *s;
  981. {
  982.     struct termio termio;
  983.     int r, retry = 0, i = 0;
  984.     static int error = 0;        /* error occurred on last call */
  985.     while((i < n) && (retry < RETRY)) {
  986.         if(locked()) uuexit(0);
  987.         errno = 0;
  988.         if(r = write(f, s + i, 1) == 1) i++;    /* Success! */
  989.         else {
  990.             retry++;
  991.             fixline();
  992.         }
  993. #ifdef SLOW
  994.         sleep(1);        /* Let the modem deal with it */
  995. #endif
  996.     }
  997.     if(i != n) {
  998.         ioctl(dev, TCGETA, &termio);
  999.         printf("Tried %d times, still got %d/%d written. [error = %s]\n", 
  1000.             retry, i, n, sys_errlist[errno]);
  1001.         printf("FAIL: dev %d, iflag %x, oflag %x, cflag %x, lflag %x, line %d\n",
  1002.             dev, termio.c_iflag,termio.c_oflag,termio.c_cflag,
  1003.             termio.c_lflag, termio.c_line);
  1004.         error = 1;
  1005.     }
  1006.     else if(retry > 1) printf("Write problem: fixed on retry %d\n", retry - 1);
  1007.     if(error && i == n) {
  1008.         ioctl(dev, TCGETA, &termio);
  1009.         printf("OK: iflag %x, oflag %x, cflag %x, lflag %x, line %d\n",
  1010.             termio.c_iflag,termio.c_oflag,termio.c_cflag,
  1011.             termio.c_lflag, termio.c_line);
  1012.     }
  1013.     if(i == n) error = 0;
  1014.     return(r);
  1015. }
  1016. /*
  1017.  * read one character at a time, checking before (and after) each read for
  1018.  * a lock file. If one exists, then exit.
  1019.  */
  1020. dread(f, s, n)
  1021. int f, n;
  1022. char *s;
  1023. {
  1024.     int i, w;
  1025.     for(i=0;i<n;i++, s++) {
  1026.         if(locked()) uuexit(0);
  1027.         while((w = read(f, s, 1)) < 1) {
  1028.             if(locked()) uuexit(0);
  1029.             if(w == -1) switch(errno) {
  1030.             case EINTR:
  1031.                 break;
  1032.             default:
  1033.                 perror("dread");
  1034.             }
  1035.         }
  1036.     }        
  1037. }
  1038. /*
  1039.  * hangup(): hangup the phone, and close the device.
  1040.  * I've had problems with indefinate echoes from the modem when a connection
  1041.  * has closed - my modem transmits crap. This ought to hangup the phone and
  1042.  * prevent this.
  1043.  *
  1044.  * Oct 87: This problem should now be fixed, with the introduction of the
  1045.  * DCD control from the modem - we should now receive a hangup signal when
  1046.  * the line drops.
  1047.  */
  1048. hangup(device) {
  1049.     struct termio term;
  1050.     if(ioctl(device, TCGETA, &term) == -1) perror("hangup: TCGETA");
  1051.     term.c_lflag &= ~(ECHO | ECHOE | ECHOK);
  1052.     term.c_cflag &= ~CBAUD;
  1053.     term.c_cflag |= B0;        /* hangup */
  1054.     if(ioctl(device, TCSETA, &term) == -1) perror("hangup: TCSETA");
  1055.     if(ioctl(device, TCFLSH, 2) == -1) perror("hangup: TCFLSH");
  1056.     sleep(5);        /* 5 seconds with DTR down */
  1057.     return(0);
  1058. }
  1059. /*
  1060.  * findspeed: convert ascii baud rate into termio parameter.
  1061.  */
  1062. findspeed(s)
  1063. char *s;
  1064. {
  1065.     int baud = atoi(s);
  1066.     switch(baud) {
  1067.         case 110: baud = B110;
  1068.             break;
  1069.         case 300: baud = B300;
  1070.             break;
  1071.         case 1200: baud = B1200;
  1072.             break;
  1073.         case 2400: baud = B2400;
  1074.             break;
  1075.         default:
  1076.             printf("findspeed: unknown baud rate %s\n", s);
  1077.             baud = B1200;
  1078.     }
  1079.     return(baud);
  1080. }
  1081. /*
  1082.  * uuexit: make line useable by UUCP.
  1083.  * Because UUCP is pretty determined about using a "modem", it clears CLOCAL
  1084.  * which means that it can't write any characters at this point (modem not
  1085.  * online, so DCD not asserted). Not suprisingly, it doesn't work.
  1086.  * Solution: turn it on again, while UUCP isn't looking; this seems to work
  1087.  * fine, although I'm a little puzzled about the timing: this is a 
  1088.  * definate "trial and error" solution.
  1089.  * This unfortunately also means that UUCP won't detect a line hangup, 
  1090.  * so we have to rely on it's timeout facilities ...
  1091.  */
  1092. #define DIALTIME 5        /* time to continue to assert CLOCAL */
  1093. uuexit(code)
  1094. {
  1095.     struct termio term;
  1096.     register int i;
  1097.     for(i=0;i<DIALTIME;i++) {
  1098.         close(open(dname, O_RDONLY | O_NDELAY)); /* vital magic */
  1099.         if(ioctl(dev, TCGETA, &term) == -1) perror("qx TCGETA");
  1100.         term.c_cflag |= CLOCAL;
  1101.         if(ioctl(dev, TCSETA, &term) == -1) perror("qx TCSETA");
  1102.         close(open(dname, O_RDONLY | O_NDELAY)); /* vital magic */
  1103.         sleep(1);
  1104.     }
  1105.     exit(code);
  1106. }
  1107. /*
  1108.  * extensions for send & expect
  1109.  */
  1110. myread()
  1111. {
  1112.     char c;
  1113.     dread(dev, &c, 1);
  1114.     return(c);
  1115. }
  1116. void mywrite(s)
  1117. char *s;
  1118. {
  1119.     dwrite(dev, s, strlen(s));
  1120. }
  1121.  
  1122. SHAR_EOF
  1123. if test 4690 -ne "`wc -c < 'io.c'`"
  1124. then
  1125.     echo shar: "error transmitting 'io.c'" '(should have been 4690 characters)'
  1126. fi
  1127. fi
  1128. echo shar: "extracting 'line.c'" '(2338 characters)'
  1129. if test -f 'line.c'
  1130. then
  1131.     echo shar: "will not over-write existing file 'line.c'"
  1132. else
  1133. cat << \SHAR_EOF > 'line.c'
  1134. /*
  1135.  * line.c: set up the various termio params for the line at various stages.
  1136.  * [What I would like for Christmas: System V tty driver code, so I could
  1137.  *  find out why it behaves so strangely ... ]
  1138.  */
  1139.  
  1140. #include "modem.h"
  1141. #include <termio.h>
  1142. #include <fcntl.h>
  1143.  
  1144. static struct termio term;
  1145. static int speed;
  1146.  
  1147. init_term(device, baud)
  1148. int device, baud;
  1149. {
  1150.     speed = baud;
  1151.     if(ioctl(device, TCGETA, &term) == -1) perror("TCGETA");
  1152.     term.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK);
  1153.     term.c_iflag &= ~(ISTRIP | INPCK);
  1154.     term.c_cflag &= ~(CBAUD | CSIZE);
  1155.     term.c_cflag |= baud | CS8 | CLOCAL;
  1156.     term.c_cc[VMIN] = 1;
  1157.     term.c_cc[VTIME] = 0;
  1158.      if(ioctl(device, TCSETA, &term) == -1) perror("TCSETA");
  1159. /*
  1160.  * Since we opened the line with O_NDELAY, reads will return immediately if
  1161.  * no chars are ready. We don't really want this, 'cos "dread" will then
  1162.  * eat CPU time, so we turn it off.
  1163.  * It only seems to be really effective when the device is opened again -
  1164.  * otherwise we get strange diagnostics about "wrote 0 of 4". Thanks to
  1165.  * the C-KERMIT crew for this tip.
  1166.  *
  1167.  * The open() here seems to hang sometimes, so a timeout is implemented.
  1168.  * [since CLOCAL has been set above, this should never happen. We can't
  1169.  *  just open with O_NDELAY, because uucp won't work anyway.]
  1170.  */
  1171.      fcntl(device, F_SETFL, 0);
  1172.      alarm(5);
  1173.      if(close(open(dname, O_RDONLY)) == -1 ) {
  1174.          printf("** Error: Couldn't reopen device after TCSETA\n");
  1175.          exit(1);
  1176.      }
  1177.      alarm(0);
  1178. }
  1179. /*
  1180.  * Strange things have been known to happen during "login" with incorrect 
  1181.  * settings - if it forgets to ask you for a password, check them carefully.
  1182.  * Oct 87: Disable CLOCAL, since DCD is now asserted, and we want to be told
  1183.  * about hangups.
  1184.  */
  1185. login_term(device, baud)
  1186. int device, baud;
  1187. {
  1188.     ioctl(device, TCGETA, &term);
  1189.     term.c_cc[VEOF] = 04;        /* cntrl-D */
  1190.     term.c_iflag = BRKINT | IGNPAR | ISTRIP | ICRNL;
  1191.     term.c_oflag = OPOST | ONLCR | TAB3;
  1192.     term.c_cflag &= ~(CSIZE | CLOCAL | CBAUD);
  1193.     term.c_cflag |= CS7 | HUPCL | CREAD | baud;
  1194.     term.c_lflag = ISIG | ICANON;
  1195.     ioctl(device, TCSETAW, &term);
  1196. }
  1197. /*
  1198.  * fixline: write failed - redo settings on line.
  1199.  */
  1200. fixline(){
  1201.     ioctl(dev, TCFLSH, 2);        /* flush queues */
  1202.     ioctl(dev, TCXONC, 1);        /* restart XON/XOFF */
  1203.     fcntl(dev, F_SETFL, 0);        /* poke the flag */
  1204.     close(open(dname, O_RDONLY | O_NDELAY));
  1205.     init_term(dev, speed);
  1206. }
  1207.     
  1208. SHAR_EOF
  1209. if test 2338 -ne "`wc -c < 'line.c'`"
  1210. then
  1211.     echo shar: "error transmitting 'line.c'" '(should have been 2338 characters)'
  1212. fi
  1213. fi
  1214. echo shar: "extracting 'statelook.c'" '(3302 characters)'
  1215. if test -f 'statelook.c'
  1216. then
  1217.     echo shar: "will not over-write existing file 'statelook.c'"
  1218. else
  1219. cat << \SHAR_EOF > 'statelook.c'
  1220. /*
  1221.  * Stuff to work out when to next change state (causes exit)
  1222.  * and whether to apply a particular bit of the modem conversation.
  1223.  */
  1224.  
  1225. #include <time.h>
  1226.  
  1227. #include "modem.h"
  1228. #ifdef STATES
  1229.  
  1230. #define    SECS_IN_WEEK        (60L * 60L * 24L * 7L)
  1231. #define WEEK_TIME(d,h,m)    ((((long)d*24L+(long)h)*60L+(long)m)*60L)
  1232. #define EVENT_LEN        (sizeof(week_event)/sizeof(struct event))
  1233. #define IND_LEN            (sizeof(ind_tab)/sizeof(struct ind))
  1234.  
  1235. /*
  1236.     This is a table of when to turn on and off the autoanswer mode
  1237.     of the modem.
  1238. */
  1239. struct event {
  1240.     long s_time;
  1241.     int s_state;
  1242. } week_event[] = {
  1243.        { WEEK_TIME (0,  7, 35), AA | SPK }, /* AA on, speaker on   7:35 Sun */
  1244.        { WEEK_TIME (0, 22, 00), AA },       /* AA on, speaker off 22:00 Sun */
  1245.     { WEEK_TIME (1,  7, 35), SPK },      /* AA off, speaker on  7:35 Mon */
  1246.        { WEEK_TIME (1, 17, 25), AA | SPK }, /* AA on, speaker on  17:25 Mon */
  1247.        { WEEK_TIME (1, 22, 00), AA },       /* AA on, speaker off 22:00 Mon */
  1248.     { WEEK_TIME (2,  7, 35), SPK },      /* AA off, speaker on  7:35 Tue */
  1249.        { WEEK_TIME (2, 17, 25), AA | SPK }, /* AA on, speaker on  17:25 Tue */
  1250.        { WEEK_TIME (2, 22, 00), AA },       /* AA on, speaker off 22:00 Tue */
  1251.     { WEEK_TIME (3,  7, 35), SPK },      /* AA off, speaker on  7:35 Wed */
  1252.        { WEEK_TIME (3, 17, 25), AA | SPK }, /* AA on, speaker on  17:25 Wed */
  1253.        { WEEK_TIME (3, 22, 00), AA },       /* AA on, speaker off 22:00 Wed */
  1254.     { WEEK_TIME (4,  7, 35), SPK },      /* AA off, speaker on  7:35 Thu */
  1255.        { WEEK_TIME (4, 17, 25), AA | SPK }, /* AA on, speaker on  17:25 Thu */
  1256.        { WEEK_TIME (4, 22, 00), AA },       /* AA on, speaker off 22:00 Thu */
  1257.     { WEEK_TIME (5,  7, 35), SPK },      /* AA off, speaker on  7:35 Fri */
  1258.        { WEEK_TIME (5, 17, 25), AA | SPK }, /* AA on, speaker on  17:25 Fri */
  1259.        { WEEK_TIME (5, 22, 00), AA },       /* AA on, speaker off 22:00 Fri */
  1260.        { WEEK_TIME (6,  7, 35), AA | SPK }, /* AA on, speaker on   7:35 Sat */
  1261.        { WEEK_TIME (6, 22, 00), AA }        /* AA on, speaker off 22:00 Sat */
  1262. };
  1263.  
  1264. long duration(state)
  1265. int *state;            /* 0 if new Auto Answer state is OFF, 1 if ON */
  1266. {
  1267.     long secs_into_week;    /* Seconds since midnight Sunday morning */
  1268.     long t;
  1269.     struct tm *cur_time;
  1270.     int i, index;
  1271.     long delta, tst_delta;
  1272.  
  1273.     t = time((long *) 0);
  1274.     cur_time = localtime (&t);
  1275.  
  1276.     secs_into_week = ((((long)(cur_time->tm_wday)) * 24L + 
  1277.         (long)(cur_time->tm_hour)) * 60L +
  1278.         (long)(cur_time->tm_min)) * 60L + 
  1279.         (long)(cur_time->tm_sec);
  1280.  
  1281.     delta = SECS_IN_WEEK + 1; /* SOMETHING has to be closer than this! */
  1282.  
  1283.     /* Loop looking for an entry with a better delta (closer to now) */
  1284.  
  1285.     for (i=0; i < EVENT_LEN; i++) {
  1286.         tst_delta = week_event[i].s_time - secs_into_week;
  1287.         if (tst_delta < 0L)
  1288.             tst_delta += SECS_IN_WEEK; /* Adjust for wrap around */
  1289.         if (tst_delta < delta) {
  1290.             /* We found a closer event to now */
  1291.             delta = tst_delta;
  1292.             index = i;
  1293.         }
  1294.     }
  1295.     /*
  1296.      * Decrement index by one circularly (note table MUST be in order) --
  1297.      */
  1298.     if (index-- == 0)
  1299.         index = EVENT_LEN-1;
  1300.     *state = week_event[index].s_state;
  1301. #ifdef DEBUG
  1302.     printf("Currently in state %d.  Will change in %ld seconds\n",
  1303.         *state, delta);
  1304. #endif
  1305.     return(delta);
  1306. }
  1307.  
  1308. /*
  1309.     This routine decides whether a particular init line should be executed.
  1310. */
  1311. applicable(p, state)
  1312. struct conv *p;
  1313. int state;
  1314. {
  1315.     return(p->c_flags & state);
  1316. }
  1317.  
  1318. #endif
  1319. SHAR_EOF
  1320. if test 3302 -ne "`wc -c < 'statelook.c'`"
  1321. then
  1322.     echo shar: "error transmitting 'statelook.c'" '(should have been 3302 characters)'
  1323. fi
  1324. fi
  1325. exit 0
  1326. #    End of shell archive
  1327.  
  1328.     
  1329. --
  1330.  
  1331. Dave Settle, 
  1332.     SMB Business Software, Thorn EMI Datasolve, High St, Mansfield, UK
  1333.  
  1334. UUCP:    dave@smb.co.uk
  1335.     ...!mcvax!ukc!nott-cs!smb!dave    
  1336.  
  1337.         <--- This way to point of view --->
  1338.  
  1339.